using System;
using System.Collections.Generic;
using UnityEngine;
using NativeWebSocket;
using Google.Protobuf;

public class NetworkManager : MonoBehaviour
{
    public static NetworkManager Instance { get; private set; }

    [SerializeField] private string serverUrl = "ws://localhost:9090/ws";
    
    private WebSocket webSocket;
    private Queue<Action> mainThreadActions = new Queue<Action>();
    private bool isConnected = false;
    private float heartbeatInterval = 30f;
    private float lastHeartbeatTime;

    // 消息回调
    public event Action<LoginResponse> OnLoginResponse;
    public event Action<MatchResponse> OnMatchResponse;
    public event Action<MatchSuccess> OnMatchSuccess;
    public event Action<GameStart> OnGameStart;
    public event Action<PlacePieceResponse> OnPlacePieceResponse;
    public event Action<GameOverSync> OnGameOver;
    public event Action<ErrorMessage> OnError;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    private void Start()
    {
        ConnectToServer();
    }

    private void Update()
    {
        // 处理主线程消息
        lock (mainThreadActions)
        {
            while (mainThreadActions.Count > 0)
            {
                mainThreadActions.Dequeue()?.Invoke();
            }
        }

        // WebSocket消息分发
        #if !UNITY_WEBGL || UNITY_EDITOR
        if (webSocket != null)
        {
            webSocket.DispatchMessageQueue();
        }
        #endif

        // 心跳
        if (isConnected && Time.time - lastHeartbeatTime > heartbeatInterval)
        {
            SendHeartbeat();
            lastHeartbeatTime = Time.time;
        }
    }

    public async void ConnectToServer()
    {
        try
        {
            webSocket = new WebSocket(serverUrl);

            webSocket.OnOpen += () =>
            {
                Debug.Log("WebSocket连接成功");
                isConnected = true;
                lastHeartbeatTime = Time.time;
            };

            webSocket.OnError += (e) =>
            {
                Debug.LogError($"WebSocket错误: {e}");
                isConnected = false;
            };

            webSocket.OnClose += (e) =>
            {
                Debug.Log($"WebSocket关闭: {e}");
                isConnected = false;
            };

            webSocket.OnMessage += (bytes) =>
            {
                HandleMessage(bytes);
            };

            await webSocket.Connect();
        }
        catch (Exception e)
        {
            Debug.LogError($"连接服务器失败: {e.Message}");
        }
    }

    private void HandleMessage(byte[] bytes)
    {
        try
        {
            GameMessage message = GameMessage.Parser.ParseFrom(bytes);
            
            lock (mainThreadActions)
            {
                mainThreadActions.Enqueue(() => ProcessMessage(message));
            }
        }
        catch (Exception e)
        {
            Debug.LogError($"解析消息失败: {e.Message}");
        }
    }

    private void ProcessMessage(GameMessage message)
    {
        try
        {
            switch (message.Type)
            {
                case MessageType.LoginResponse:
                    OnLoginResponse?.Invoke(LoginResponse.Parser.ParseFrom(message.Data));
                    break;
                case MessageType.MatchResponse:
                    OnMatchResponse?.Invoke(MatchResponse.Parser.ParseFrom(message.Data));
                    break;
                case MessageType.MatchSuccess:
                    OnMatchSuccess?.Invoke(MatchSuccess.Parser.ParseFrom(message.Data));
                    break;
                case MessageType.GameStart:
                    OnGameStart?.Invoke(GameStart.Parser.ParseFrom(message.Data));
                    break;
                case MessageType.PlacePieceResponse:
                    OnPlacePieceResponse?.Invoke(PlacePieceResponse.Parser.ParseFrom(message.Data));
                    break;
                case MessageType.GameOverSync:
                    OnGameOver?.Invoke(GameOverSync.Parser.ParseFrom(message.Data));
                    break;
                case MessageType.Error:
                    OnError?.Invoke(ErrorMessage.Parser.ParseFrom(message.Data));
                    break;
                case MessageType.Heartbeat:
                    // 心跳响应
                    break;
                default:
                    Debug.LogWarning($"未处理的消息类型: {message.Type}");
                    break;
            }
        }
        catch (Exception e)
        {
            Debug.LogError($"处理消息失败: {e.Message}");
        }
    }

    private async void SendMessage(MessageType type, IMessage data)
    {
        if (webSocket == null || webSocket.State != WebSocketState.Open)
        {
            Debug.LogError("WebSocket未连接");
            return;
        }

        try
        {
            GameMessage message = new GameMessage
            {
                Type = type,
                Data = data.ToByteString()
            };

            await webSocket.Send(message.ToByteArray());
        }
        catch (Exception e)
        {
            Debug.LogError($"发送消息失败: {e.Message}");
        }
    }

    // API方法
    public void Login(string username, string password)
    {
        LoginRequest request = new LoginRequest
        {
            Username = username,
            Password = password
        };
        SendMessage(MessageType.LoginRequest, request);
    }

    public void RequestMatch()
    {
        MatchRequest request = new MatchRequest();
        SendMessage(MessageType.MatchRequest, request);
    }

    public void CancelMatch()
    {
        CancelMatchRequest request = new CancelMatchRequest();
        SendMessage(MessageType.CancelMatch, request);
    }

    public void PlacePiece(int row, int col)
    {
        PlacePieceRequest request = new PlacePieceRequest
        {
            Row = row,
            Col = col
        };
        SendMessage(MessageType.PlacePiece, request);
    }

    public void Surrender()
    {
        SurrenderRequest request = new SurrenderRequest();
        SendMessage(MessageType.Surrender, request);
    }

    private void SendHeartbeat()
    {
        HeartbeatRequest heartbeat = new HeartbeatRequest
        {
            Timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
        };
        SendMessage(MessageType.Heartbeat, heartbeat);
    }

    private async void OnApplicationQuit()
    {
        if (webSocket != null)
        {
            await webSocket.Close();
        }
    }
}
